package org.dromara.ai.error;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.ai.domain.dto.AiChatRequest;
import org.dromara.ai.domain.dto.AiChatResponse;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * AI错误处理和故障恢复服务
 * 提供统一的错误处理、重试机制和故障恢复功能
 *
 * @author RuoYi
 * @since 2024-01-01
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AiErrorHandler {

    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
    
    // 错误统计
    private final Map<String, ErrorStatistics> errorStats = new ConcurrentHashMap<>();
    
    // 熔断器状态
    private final Map<String, CircuitBreakerState> circuitBreakers = new ConcurrentHashMap<>();
    
    // 重试配置
    private final Map<String, RetryConfig> retryConfigs = new ConcurrentHashMap<>();
    
    /**
     * 错误类型枚举
     */
    public enum ErrorType {
        NETWORK_ERROR,          // 网络错误
        TIMEOUT_ERROR,          // 超时错误
        RATE_LIMIT_ERROR,       // 速率限制错误
        QUOTA_EXCEEDED_ERROR,   // 配额超限错误
        AUTHENTICATION_ERROR,   // 认证错误
        AUTHORIZATION_ERROR,    // 授权错误
        VALIDATION_ERROR,       // 验证错误
        SERVICE_UNAVAILABLE,    // 服务不可用
        INTERNAL_ERROR,         // 内部错误
        UNKNOWN_ERROR           // 未知错误
    }
    
    /**
     * 错误严重级别
     */
    public enum ErrorSeverity {
        LOW,        // 低级别
        MEDIUM,     // 中级别
        HIGH,       // 高级别
        CRITICAL    // 严重级别
    }
    
    /**
     * 熔断器状态
     */
    public enum CircuitBreakerStatus {
        CLOSED,     // 关闭状态（正常）
        OPEN,       // 开启状态（熔断）
        HALF_OPEN   // 半开状态（试探）
    }
    
    /**
     * 错误信息类
     */
    public static class AiError {
        private String id;
        private ErrorType type;
        private ErrorSeverity severity;
        private String message;
        private String details;
        private String provider;
        private String model;
        private String userId;
        private LocalDateTime occurTime;
        private Map<String, Object> context;
        private Throwable cause;
        
        // Getters and Setters
        public String getId() { return id; }
        public AiError setId(String id) { this.id = id; return this; }
        
        public ErrorType getType() { return type; }
        public AiError setType(ErrorType type) { this.type = type; return this; }
        
        public ErrorSeverity getSeverity() { return severity; }
        public AiError setSeverity(ErrorSeverity severity) { this.severity = severity; return this; }
        
        public String getMessage() { return message; }
        public AiError setMessage(String message) { this.message = message; return this; }
        
        public String getDetails() { return details; }
        public AiError setDetails(String details) { this.details = details; return this; }
        
        public String getProvider() { return provider; }
        public AiError setProvider(String provider) { this.provider = provider; return this; }
        
        public String getModel() { return model; }
        public AiError setModel(String model) { this.model = model; return this; }
        
        public String getUserId() { return userId; }
        public AiError setUserId(String userId) { this.userId = userId; return this; }
        
        public LocalDateTime getOccurTime() { return occurTime; }
        public AiError setOccurTime(LocalDateTime occurTime) { this.occurTime = occurTime; return this; }
        
        public Map<String, Object> getContext() { return context; }
        public AiError setContext(Map<String, Object> context) { this.context = context; return this; }
        
        public Throwable getCause() { return cause; }
        public AiError setCause(Throwable cause) { this.cause = cause; return this; }
    }
    
    /**
     * 错误统计类
     */
    public static class ErrorStatistics {
        private String key;
        private long totalErrors;
        private long networkErrors;
        private long timeoutErrors;
        private long rateLimitErrors;
        private long quotaErrors;
        private long authErrors;
        private long validationErrors;
        private long serviceUnavailableErrors;
        private long internalErrors;
        private long unknownErrors;
        private LocalDateTime lastErrorTime;
        private LocalDateTime firstErrorTime;
        private double errorRate;
        
        public ErrorStatistics(String key) {
            this.key = key;
            this.firstErrorTime = LocalDateTime.now();
        }
        
        public void incrementError(ErrorType type) {
            totalErrors++;
            lastErrorTime = LocalDateTime.now();
            
            switch (type) {
                case NETWORK_ERROR -> networkErrors++;
                case TIMEOUT_ERROR -> timeoutErrors++;
                case RATE_LIMIT_ERROR -> rateLimitErrors++;
                case QUOTA_EXCEEDED_ERROR -> quotaErrors++;
                case AUTHENTICATION_ERROR, AUTHORIZATION_ERROR -> authErrors++;
                case VALIDATION_ERROR -> validationErrors++;
                case SERVICE_UNAVAILABLE -> serviceUnavailableErrors++;
                case INTERNAL_ERROR -> internalErrors++;
                default -> unknownErrors++;
            }
        }
        
        // Getters
        public String getKey() { return key; }
        public long getTotalErrors() { return totalErrors; }
        public long getNetworkErrors() { return networkErrors; }
        public long getTimeoutErrors() { return timeoutErrors; }
        public long getRateLimitErrors() { return rateLimitErrors; }
        public long getQuotaErrors() { return quotaErrors; }
        public long getAuthErrors() { return authErrors; }
        public long getValidationErrors() { return validationErrors; }
        public long getServiceUnavailableErrors() { return serviceUnavailableErrors; }
        public long getInternalErrors() { return internalErrors; }
        public long getUnknownErrors() { return unknownErrors; }
        public LocalDateTime getLastErrorTime() { return lastErrorTime; }
        public LocalDateTime getFirstErrorTime() { return firstErrorTime; }
        public double getErrorRate() { return errorRate; }
        public void setErrorRate(double errorRate) { this.errorRate = errorRate; }
    }
    
    /**
     * 熔断器状态类
     */
    public static class CircuitBreakerState {
        private String key;
        private CircuitBreakerStatus status;
        private long failureCount;
        private long successCount;
        private LocalDateTime lastFailureTime;
        private LocalDateTime lastSuccessTime;
        private LocalDateTime nextRetryTime;
        private int failureThreshold;
        private int successThreshold;
        private long timeoutMs;
        
        public CircuitBreakerState(String key) {
            this.key = key;
            this.status = CircuitBreakerStatus.CLOSED;
            this.failureThreshold = 5;
            this.successThreshold = 3;
            this.timeoutMs = 60000; // 1分钟
        }
        
        public void recordSuccess() {
            successCount++;
            lastSuccessTime = LocalDateTime.now();
            
            if (status == CircuitBreakerStatus.HALF_OPEN && successCount >= successThreshold) {
                status = CircuitBreakerStatus.CLOSED;
                failureCount = 0;
                successCount = 0;
            }
        }
        
        public void recordFailure() {
            failureCount++;
            lastFailureTime = LocalDateTime.now();
            
            if (status == CircuitBreakerStatus.CLOSED && failureCount >= failureThreshold) {
                status = CircuitBreakerStatus.OPEN;
                nextRetryTime = LocalDateTime.now().plusNanos(timeoutMs * 1_000_000);
            } else if (status == CircuitBreakerStatus.HALF_OPEN) {
                status = CircuitBreakerStatus.OPEN;
                nextRetryTime = LocalDateTime.now().plusNanos(timeoutMs * 1_000_000);
                successCount = 0;
            }
        }
        
        public boolean canExecute() {
            if (status == CircuitBreakerStatus.CLOSED) {
                return true;
            } else if (status == CircuitBreakerStatus.OPEN) {
                if (LocalDateTime.now().isAfter(nextRetryTime)) {
                    status = CircuitBreakerStatus.HALF_OPEN;
                    return true;
                }
                return false;
            } else { // HALF_OPEN
                return true;
            }
        }
        
        // Getters
        public String getKey() { return key; }
        public CircuitBreakerStatus getStatus() { return status; }
        public long getFailureCount() { return failureCount; }
        public long getSuccessCount() { return successCount; }
        public LocalDateTime getLastFailureTime() { return lastFailureTime; }
        public LocalDateTime getLastSuccessTime() { return lastSuccessTime; }
        public LocalDateTime getNextRetryTime() { return nextRetryTime; }
    }
    
    /**
     * 重试配置类
     */
    public static class RetryConfig {
        private int maxAttempts;
        private long initialDelayMs;
        private long maxDelayMs;
        private double backoffMultiplier;
        private boolean exponentialBackoff;
        
        public RetryConfig() {
            this.maxAttempts = 3;
            this.initialDelayMs = 1000;
            this.maxDelayMs = 30000;
            this.backoffMultiplier = 2.0;
            this.exponentialBackoff = true;
        }
        
        // Getters and Setters
        public int getMaxAttempts() { return maxAttempts; }
        public RetryConfig setMaxAttempts(int maxAttempts) { this.maxAttempts = maxAttempts; return this; }
        
        public long getInitialDelayMs() { return initialDelayMs; }
        public RetryConfig setInitialDelayMs(long initialDelayMs) { this.initialDelayMs = initialDelayMs; return this; }
        
        public long getMaxDelayMs() { return maxDelayMs; }
        public RetryConfig setMaxDelayMs(long maxDelayMs) { this.maxDelayMs = maxDelayMs; return this; }
        
        public double getBackoffMultiplier() { return backoffMultiplier; }
        public RetryConfig setBackoffMultiplier(double backoffMultiplier) { this.backoffMultiplier = backoffMultiplier; return this; }
        
        public boolean isExponentialBackoff() { return exponentialBackoff; }
        public RetryConfig setExponentialBackoff(boolean exponentialBackoff) { this.exponentialBackoff = exponentialBackoff; return this; }
    }
    
    /**
     * 执行带错误处理的操作
     *
     * @param key 操作标识
     * @param operation 操作函数
     * @param request 请求对象
     * @return 响应结果
     */
    public AiChatResponse executeWithErrorHandling(String key, 
                                                   Function<AiChatRequest, AiChatResponse> operation,
                                                   AiChatRequest request) {
        CircuitBreakerState circuitBreaker = getOrCreateCircuitBreaker(key);
        
        // 检查熔断器状态
        if (!circuitBreaker.canExecute()) {
            AiError error = new AiError()
                .setType(ErrorType.SERVICE_UNAVAILABLE)
                .setSeverity(ErrorSeverity.HIGH)
                .setMessage("服务熔断中，暂时不可用")
                .setProvider(key)
                .setUserId(request.getUserId())
                .setOccurTime(LocalDateTime.now());
            
            recordError(key, error);
            return createErrorResponse(error, request);
        }
        
        RetryConfig retryConfig = getOrCreateRetryConfig(key);
        
        for (int attempt = 1; attempt <= retryConfig.getMaxAttempts(); attempt++) {
            try {
                AiChatResponse response = operation.apply(request);
                
                if (response.getSuccess() != null && response.getSuccess()) {
                    circuitBreaker.recordSuccess();
                    return response;
                } else {
                    // 业务错误
                    AiError error = createErrorFromResponse(response, request);
                    recordError(key, error);
                    
                    if (attempt == retryConfig.getMaxAttempts() || !isRetryableError(error.getType())) {
                        circuitBreaker.recordFailure();
                        return response;
                    }
                }
                
            } catch (Exception e) {
                AiError error = createErrorFromException(e, key, request);
                recordError(key, error);
                
                if (attempt == retryConfig.getMaxAttempts() || !isRetryableError(error.getType())) {
                    circuitBreaker.recordFailure();
                    return createErrorResponse(error, request);
                }
                
                // 等待重试
                if (attempt < retryConfig.getMaxAttempts()) {
                    try {
                        long delay = calculateRetryDelay(retryConfig, attempt);
                        Thread.sleep(delay);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        }
        
        // 所有重试都失败
        AiError error = new AiError()
            .setType(ErrorType.INTERNAL_ERROR)
            .setSeverity(ErrorSeverity.HIGH)
            .setMessage("所有重试尝试都失败")
            .setProvider(key)
            .setUserId(request.getUserId())
            .setOccurTime(LocalDateTime.now());
        
        circuitBreaker.recordFailure();
        return createErrorResponse(error, request);
    }
    
    /**
     * 记录错误
     *
     * @param key 错误标识
     * @param error 错误信息
     */
    public void recordError(String key, AiError error) {
        ErrorStatistics stats = errorStats.computeIfAbsent(key, ErrorStatistics::new);
        stats.incrementError(error.getType());
        
        log.error("AI错误记录 - Key: {}, Type: {}, Severity: {}, Message: {}", 
                 key, error.getType(), error.getSeverity(), error.getMessage());
        
        // 根据错误严重级别进行不同处理
        switch (error.getSeverity()) {
            case CRITICAL -> handleCriticalError(error);
            case HIGH -> handleHighSeverityError(error);
            case MEDIUM -> handleMediumSeverityError(error);
            case LOW -> handleLowSeverityError(error);
        }
    }
    
    /**
     * 获取错误统计
     *
     * @param key 统计标识
     * @return 错误统计
     */
    public ErrorStatistics getErrorStatistics(String key) {
        return errorStats.get(key);
    }
    
    /**
     * 获取所有错误统计
     *
     * @return 错误统计映射
     */
    public Map<String, ErrorStatistics> getAllErrorStatistics() {
        return new ConcurrentHashMap<>(errorStats);
    }
    
    /**
     * 获取熔断器状态
     *
     * @param key 熔断器标识
     * @return 熔断器状态
     */
    public CircuitBreakerState getCircuitBreakerState(String key) {
        return circuitBreakers.get(key);
    }
    
    /**
     * 重置熔断器
     *
     * @param key 熔断器标识
     */
    public void resetCircuitBreaker(String key) {
        CircuitBreakerState state = circuitBreakers.get(key);
        if (state != null) {
            state.status = CircuitBreakerStatus.CLOSED;
            state.failureCount = 0;
            state.successCount = 0;
            log.info("熔断器已重置: {}", key);
        }
    }
    
    /**
     * 设置重试配置
     *
     * @param key 配置标识
     * @param config 重试配置
     */
    public void setRetryConfig(String key, RetryConfig config) {
        retryConfigs.put(key, config);
    }
    
    /**
     * 清理错误统计
     */
    public void clearErrorStatistics() {
        errorStats.clear();
        log.info("错误统计已清理");
    }
    
    /**
     * 获取或创建熔断器
     */
    private CircuitBreakerState getOrCreateCircuitBreaker(String key) {
        return circuitBreakers.computeIfAbsent(key, CircuitBreakerState::new);
    }
    
    /**
     * 获取或创建重试配置
     */
    private RetryConfig getOrCreateRetryConfig(String key) {
        return retryConfigs.computeIfAbsent(key, k -> new RetryConfig());
    }
    
    /**
     * 判断是否为可重试错误
     */
    private boolean isRetryableError(ErrorType errorType) {
        return switch (errorType) {
            case NETWORK_ERROR, TIMEOUT_ERROR, SERVICE_UNAVAILABLE, RATE_LIMIT_ERROR -> true;
            case AUTHENTICATION_ERROR, AUTHORIZATION_ERROR, VALIDATION_ERROR, QUOTA_EXCEEDED_ERROR -> false;
            default -> true;
        };
    }
    
    /**
     * 计算重试延迟
     */
    private long calculateRetryDelay(RetryConfig config, int attempt) {
        if (!config.isExponentialBackoff()) {
            return config.getInitialDelayMs();
        }
        
        long delay = (long) (config.getInitialDelayMs() * Math.pow(config.getBackoffMultiplier(), attempt - 1));
        return Math.min(delay, config.getMaxDelayMs());
    }
    
    /**
     * 从异常创建错误对象
     */
    private AiError createErrorFromException(Exception e, String provider, AiChatRequest request) {
        ErrorType type = classifyException(e);
        ErrorSeverity severity = determineSeverity(type);
        
        return new AiError()
            .setId(java.util.UUID.randomUUID().toString())
            .setType(type)
            .setSeverity(severity)
            .setMessage(e.getMessage())
            .setDetails(getStackTrace(e))
            .setProvider(provider)
            .setModel(request.getModel())
            .setUserId(request.getUserId())
            .setOccurTime(LocalDateTime.now())
            .setCause(e);
    }
    
    /**
     * 从响应创建错误对象
     */
    private AiError createErrorFromResponse(AiChatResponse response, AiChatRequest request) {
        ErrorType type = classifyResponseError(response);
        ErrorSeverity severity = determineSeverity(type);
        
        return new AiError()
            .setId(java.util.UUID.randomUUID().toString())
            .setType(type)
            .setSeverity(severity)
            .setMessage(response.getError())
            .setDetails(response.getErrorCode())
            .setProvider(response.getProvider())
            .setModel(response.getModel())
            .setUserId(request.getUserId())
            .setOccurTime(LocalDateTime.now());
    }
    
    /**
     * 分类异常类型
     */
    private ErrorType classifyException(Exception e) {
        String message = e.getMessage();
        if (message == null) {
            return ErrorType.UNKNOWN_ERROR;
        }
        
        message = message.toLowerCase();
        
        if (message.contains("timeout") || message.contains("timed out")) {
            return ErrorType.TIMEOUT_ERROR;
        } else if (message.contains("network") || message.contains("connection")) {
            return ErrorType.NETWORK_ERROR;
        } else if (message.contains("rate limit") || message.contains("too many requests")) {
            return ErrorType.RATE_LIMIT_ERROR;
        } else if (message.contains("quota") || message.contains("limit exceeded")) {
            return ErrorType.QUOTA_EXCEEDED_ERROR;
        } else if (message.contains("unauthorized") || message.contains("authentication")) {
            return ErrorType.AUTHENTICATION_ERROR;
        } else if (message.contains("forbidden") || message.contains("access denied")) {
            return ErrorType.AUTHORIZATION_ERROR;
        } else if (message.contains("validation") || message.contains("invalid")) {
            return ErrorType.VALIDATION_ERROR;
        } else if (message.contains("service unavailable") || message.contains("server error")) {
            return ErrorType.SERVICE_UNAVAILABLE;
        } else {
            return ErrorType.INTERNAL_ERROR;
        }
    }
    
    /**
     * 分类响应错误类型
     */
    private ErrorType classifyResponseError(AiChatResponse response) {
        String errorCode = response.getErrorCode();
        String errorMessage = response.getError();
        
        if (errorCode != null) {
            return switch (errorCode.toUpperCase()) {
                case "TIMEOUT", "TIMEOUT_ERROR" -> ErrorType.TIMEOUT_ERROR;
                case "RATE_LIMIT", "RATE_LIMIT_ERROR" -> ErrorType.RATE_LIMIT_ERROR;
                case "QUOTA_EXCEEDED" -> ErrorType.QUOTA_EXCEEDED_ERROR;
                case "AUTH_ERROR", "AUTHENTICATION_ERROR" -> ErrorType.AUTHENTICATION_ERROR;
                case "AUTHORIZATION_ERROR" -> ErrorType.AUTHORIZATION_ERROR;
                case "VALIDATION_ERROR" -> ErrorType.VALIDATION_ERROR;
                case "SERVICE_UNAVAILABLE" -> ErrorType.SERVICE_UNAVAILABLE;
                case "NETWORK_ERROR" -> ErrorType.NETWORK_ERROR;
                default -> ErrorType.INTERNAL_ERROR;
            };
        }
        
        if (errorMessage != null) {
            return classifyException(new RuntimeException(errorMessage));
        }
        
        return ErrorType.UNKNOWN_ERROR;
    }
    
    /**
     * 确定错误严重级别
     */
    private ErrorSeverity determineSeverity(ErrorType errorType) {
        return switch (errorType) {
            case AUTHENTICATION_ERROR, AUTHORIZATION_ERROR -> ErrorSeverity.CRITICAL;
            case SERVICE_UNAVAILABLE, QUOTA_EXCEEDED_ERROR -> ErrorSeverity.HIGH;
            case NETWORK_ERROR, TIMEOUT_ERROR, RATE_LIMIT_ERROR -> ErrorSeverity.MEDIUM;
            case VALIDATION_ERROR -> ErrorSeverity.LOW;
            default -> ErrorSeverity.MEDIUM;
        };
    }
    
    /**
     * 创建错误响应
     */
    private AiChatResponse createErrorResponse(AiError error, AiChatRequest request) {
        return new AiChatResponse()
            .setSuccess(false)
            .setError(error.getMessage())
            .setErrorCode(error.getType().name())
            .setModel(request.getModel())
            .setProvider(error.getProvider())
            .setCreateTime(LocalDateTime.now());
    }
    
    /**
     * 获取异常堆栈信息
     */
    private String getStackTrace(Exception e) {
        java.io.StringWriter sw = new java.io.StringWriter();
        java.io.PrintWriter pw = new java.io.PrintWriter(sw);
        e.printStackTrace(pw);
        return sw.toString();
    }
    
    /**
     * 处理严重错误
     */
    private void handleCriticalError(AiError error) {
        log.error("严重错误发生: {}", error.getMessage());
        // 可以发送告警、通知等
    }
    
    /**
     * 处理高级别错误
     */
    private void handleHighSeverityError(AiError error) {
        log.warn("高级别错误发生: {}", error.getMessage());
        // 可以记录到特殊日志、发送通知等
    }
    
    /**
     * 处理中级别错误
     */
    private void handleMediumSeverityError(AiError error) {
        log.warn("中级别错误发生: {}", error.getMessage());
    }
    
    /**
     * 处理低级别错误
     */
    private void handleLowSeverityError(AiError error) {
        log.debug("低级别错误发生: {}", error.getMessage());
    }
    
    /**
     * 销毁资源
     */
    public void destroy() {
        if (scheduler != null && !scheduler.isShutdown()) {
            scheduler.shutdown();
            try {
                if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
                    scheduler.shutdownNow();
                }
            } catch (InterruptedException e) {
                scheduler.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
        log.info("AI错误处理器已销毁");
    }
}